package org.example.documenttool.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.spire.presentation.*;
import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.sl.usermodel.TextShape;
import org.apache.poi.xslf.usermodel.*;
import org.example.documenttool.entity.PPTDataEntity;
import org.example.documenttool.utils.OssUtils;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;


import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * PPT制作工具类
 */
@Service
public class PPTToolService {
    @Autowired
    private ChatClient zhiPuAI;
    private static int num=0;
    /**
     * 获取PPT模板结构集合
     */
    public void getPPTTemplateStructure() {
        try {
//        TODO 获取PPT文件
            InputStream pptInput=new FileInputStream("C:/Users/33416/OneDrive/文档/DEMOPPT-03.pptx");
            XMLSlideShow pptFileShow=new XMLSlideShow(pptInput);
//        TODO 获取每一张幻灯片的列表
            List<XSLFSlide> pptSlideList=pptFileShow.getSlides();
            for (XSLFSlide pptSlide : pptSlideList){
                System.out.println("Slide "+pptSlide.getSlideNumber()+" has "+pptSlide.getShapes().size()+" shapes");
//                for (XSLFShape pptShape : pptSlide.getShapes()){
//                    System.out.println("形状类型："+pptShape.getShapeName()+"-->ID-->"+pptShape.getShapeId());
//                    try {
//                        XSLFChart chart=XSLFChart.class.cast(pptShape);
//                        System.out.println("图表Title==》："+chart.getTitle());
//                    }catch (Exception e){
//                        System.out.println("不是图表\n");
//                    }
//
//                }
                for (XSLFShape pptShape : pptSlide.getShapes()){
                    System.out.println("形状类型："+pptShape.getShapeName()+"-->ID-->"+pptShape.getShapeId());

                }
//                TODO 获取文本形状信息
//                XSLFTextShape[] pptTextShapeList=pptSlide.getPlaceholders();
//                for (XSLFTextShape pptTextShape : pptTextShapeList){
//                    System.out.println("这是ShapeName:--->"+pptTextShape.getShapeName()+"Text Shape "+pptTextShape.getText());
//                }
            }
//        TODO 打印结构信息
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
    /**
     * 二级测试：测试将PPT模板中的文本框设置成JSON格式
     */
    public String setPPTTextShapeAsJson(String ossUrl) throws IOException {
        Path tempFile = Paths.get(System.getProperty("java.io.tmpdir"), "temp.pptx");
        try (InputStream in = new URL(ossUrl).openStream()) {
            Files.copy(in, tempFile, StandardCopyOption.REPLACE_EXISTING);
        }
        InputStream pptInput=new FileInputStream(tempFile.toString());
        try {
//            TODO 获取PPT文件
            XMLSlideShow pptFileShow=new XMLSlideShow(pptInput);
//            TODO 创建JSON
            ObjectMapper mapper=new ObjectMapper();
            ObjectNode pptJson=mapper.createObjectNode();
            ArrayNode pptFileArray=pptJson.putArray("pptFileName");
//            TODO 遍历每一个幻灯片
            for (XSLFSlide pptSlide: pptFileShow.getSlides()){
                ObjectNode pptSlideJson=pptFileArray.addObject();
//                TODO 创建幻灯片节点 设置值
                pptSlideJson.put("slideName",pptSlide.getSlideName());
//                TODO 设置幻灯片的每一个文本框节点
                ArrayNode pptTextShapeArray=pptSlideJson.putArray("textShape");
                for (XSLFTextShape pptTextShape: pptSlide.getPlaceholders()){
                    ObjectNode pptTextShapeJson=pptTextShapeArray.addObject();
//                    TODO 文本框名字添加到json
                    pptTextShapeJson.put("shapeName",pptTextShape.getShapeName());
//                    TODO 文本框内容设置到json
                    pptTextShapeJson.put("text",pptTextShape.getText());
                }
            }
//            TODO 输出JSON
            String json=mapper.writeValueAsString(pptJson);
            System.out.println(json);
//            TODO 关闭PPT文件
            pptInput.close();
            Files.deleteIfExists(tempFile);
            return json;
        }catch (Exception e){
            System.out.println(e.getMessage());
            Files.deleteIfExists(tempFile);
            pptInput.close();
            return "no!!!!!";
        }
    }
    /**
     * 测试编辑新的ppt
     */
    public String mapPptJSONToPPT(String pptJSON,String ossUrl)
            throws IOException, InterruptedException {
        Path tempFile = Paths.get(System.getProperty("java.io.tmpdir"), "temp2.pptx");
        try (InputStream in = new URL(ossUrl).openStream()) {
            Files.copy(in, tempFile, StandardCopyOption.REPLACE_EXISTING);
        }
            InputStream pptFile = new FileInputStream(tempFile.toString());
//        TODO 检验JSON数据是否有参杂其他错误字符
            int index = pptJSON.indexOf("{");
            int endIndex = pptJSON.lastIndexOf("}");
            if (index!=-1&&endIndex!=-1&&index<endIndex){
                String pptJsonStr=pptJSON.substring(index,endIndex+1);
                int i = 0;
//        TODO 获取ppt文件
                XMLSlideShow ppt=new XMLSlideShow(pptFile);
//        TODO 获取JSON数据
                ObjectMapper mapper = new ObjectMapper();
                JsonNode jsonNode = mapper.readTree(pptJsonStr);
                JsonNode pptFileNode = jsonNode.get("pptFileName");
                for (JsonNode slideNode : pptFileNode){
                    String slideName = slideNode.get("slideName").asText();
                    XSLFSlide slide=ppt.getSlides().get(i);
                    i++;
                    int j=0;
                    for (JsonNode textNode : slideNode.get("textShape")){
                        String text=textNode.get("text").asText();
                        XSLFTextShape textShape=slide.getPlaceholder(j);
//                        TODO 先清除所有文本框内容  预防幽灵文本错误
                        textShape.clearText();
                        textShape.setText(text);
                        j++;
                    }
                }
//        TODO 将修改后的ppt导入到临时文件
                Path pptTamPath = Files.createTempFile("pptx-temps2", ".pptx");
                OutputStream outputStream = Files.newOutputStream(pptTamPath);
                ppt.write(outputStream);
                ppt.close();
//        TODO 将临时文件导入到OSS存储
                if (OssUtils.isOssEnabled(pptTamPath, "pptx-temps"+String.valueOf(num)+".pptx")){
                    num++;
                    pptFile.close();
                    Files.deleteIfExists(pptTamPath);
                    Files.deleteIfExists(tempFile);
                    return "OSS添加ppt成功!!![https://webbook01.oss-cn-hangzhou.aliyuncs.com/pptx-temps"+String.valueOf(num)+".pptx]";
                }else {
                    pptFile.close();
                    Files.deleteIfExists(pptTamPath);
                    Files.deleteIfExists(tempFile);
                    return "OSS添加ppt失败!!!";
                }

            }else {
                pptFile.close();
                return "JSON数据有误!!!";
            }
    }
    /**
     * 三级测试
     *    将ppt每个节点依次输入大模型 生成对应数据
     */
    public String setPPTTextShapeAs() throws IOException {
        InputStream pptInput=new FileInputStream("C:/Users/33416/OneDrive/文档/DEMOPPT-02.pptx");
        try {
//            TODO 获取PPT文件
            XMLSlideShow pptFileShow=new XMLSlideShow(pptInput);
//            TODO 创建JSON
            ObjectMapper mapper=new ObjectMapper();
            ObjectNode pptJson=mapper.createObjectNode();
            ArrayNode pptFileArray=pptJson.putArray("pptFileName");
//            TODO 遍历每一个幻灯片
            for (XSLFSlide pptSlide: pptFileShow.getSlides()){
                ObjectNode pptSlideJson=pptFileArray.addObject();
//                TODO 创建幻灯片节点 设置值
                pptSlideJson.put("slideName",pptSlide.getSlideName());
                // 获取幻灯片的当前页码
                int currentPageNum=pptSlide.getSlideNumber();
//                TODO 设置幻灯片的每一个文本框节点
                ArrayNode pptTextShapeArray=pptSlideJson.putArray("textShape");
                for (XSLFTextShape pptTextShape: pptSlide.getPlaceholders()){
                    ObjectNode pptTextShapeJson=pptTextShapeArray.addObject();
//                    TODO 文本框名字添加到json
                    pptTextShapeJson.put("shapeName",pptTextShape.getShapeName());
//                    TODO 文本框内容设置到json
                    pptTextShapeJson.put("text",pptTextShape.getText());
                    // 获取当前幻灯片的输入框的属性以及要填充的内容
                    String text=pptTextShape.getText();
                    // 交给AI让ai生成内容对齐填充
                }
            }
//            TODO 输出JSON
            String json=mapper.writeValueAsString(pptJson);
            System.out.println(json);
//            TODO 关闭PPT文件
            pptInput.close();
            return json;
        }catch (Exception e){
            System.out.println(e.getMessage());
            pptInput.close();
            return "no!!!!!";
        }
    }
    /**
     * 提取幻灯片的页码以及结构
     * @param pptPath 幻灯片路径
     * @return 幻灯片的页码以及结构
     */
    public List<PPTDataEntity> getSlideStructure(String pptPath) throws IOException {
        // TODO 获取PPT文件
        InputStream pptInput=new FileInputStream(pptPath);
            XMLSlideShow pptFileShow=new XMLSlideShow(pptInput);
            List<PPTDataEntity> pptDataEntityList=new ArrayList<>();
            //TODO 遍历PPT幻灯片
            for (XSLFSlide pptSlide: pptFileShow.getSlides()){
                PPTDataEntity pptDataEntity=new PPTDataEntity();
                //TODO 获取页码
                int currentPageNum=pptSlide.getSlideNumber();
                pptDataEntity.setPageNumber(currentPageNum);
                //TODO 获取幻灯片的结构
                XSLFTextShape[] pptTextShape=pptSlide.getPlaceholders();
                for (XSLFTextShape pptShape: pptTextShape){
                    //TODO 获取形状类型
                    String shapeName=pptShape.getShapeName();
                    String text=pptShape.getText();
                    pptDataEntity.getStructure().add(shapeName+"--预设内容："+text);
                }
                pptDataEntityList.add(pptDataEntity);
            }
            System.out.println("pptDataEntityList----->: "+pptDataEntityList);
            return pptDataEntityList;
    }
    /**
     * 让AI提取幻灯组成一个新的幻灯片
     * @param pptText 已有的ppt幻灯片
     * @param text 客户需要的ppt结构
     */
    public List<PPTDataEntity> getSlideStructureByAI(List<PPTDataEntity> pptText,String text) throws IOException, InterruptedException {
        List<PPTDataEntity> pptDataEntityList = zhiPuAI.prompt("你是一个PPT幻灯片重排专家，你会根据现有的的ppt文档中的幻灯片的页码，按照原有页码为唯一标识码，组成一个新的幻灯片排列，这些编排以及顺序会尽可能地按照用户的ppt结构" +
                "输出格式务必按照：" +
                "    // 幻灯片在新的ppt中的页码\n" +
                "    private int newPageNumber;\n"+
                "    // 幻灯片在旧PPT中的页码\n" +
                "    private int pageNumber;\n" +
                "    // ppt 结构\n" +
                "    private List<String> structure=new ArrayList<>();" +
                        "可以重复使用这里的幻灯片" +
                        "最终得到一个更加丰富的更长幻灯片的ppt" +
                        "注意1：你只能使用旧ppt中已有的幻灯片结构，如果用户要求生成的内容与结构不符合，你也只可以改变内容，不能改变结构。任何擅自生成新的ppt结构都是违法的。" +
                        "注意2：生成的private int pageNumber字段坚决不可以超过旧ppt中的最大页码值，否则是违法的。" +
                        "注意3：生成的内容或者json数据中坚决 禁止出现 // 或 /* */ 等任何注释等；否则视为格式错误")
                .user(user->user.text("""
                        这是已有的旧ppt文档中的幻灯片（页码+结构）：{pptText}
                        这是客户要的ppt结构与内容：{text}
                        如果是你你会怎么重新编排这个ppt的幻灯片，来更好的存放这些数据信息
                        请生成你重新精细的编排的幻灯片顺序以及简单的内容
                        """)
                        .param("pptText", pptText)
                        .param("text", text))
                .call()
                .entity(new ParameterizedTypeReference<List<PPTDataEntity>>() {});
        return pptDataEntityList;
    }
    /**
     * 生成指定主题的PPT结构
     * @param text 主题
     */
    public String generatePPTStructure(String text) throws IOException, InterruptedException {
        String Data=zhiPuAI.prompt("你是一个相当优秀的PPT编排专家，你会根据用户输入的主题，详细的生成一个ppt结构与内容")
                .user(user->user.text("""
                        这是用户的需要生成ppt的主题：{text}
                        请生成详细的结构以及内容，我会按照这个结构来重新编排ppt文档中的幻灯片之间排序
                        """)
                        .param("text", text))
                .call()
                .content();
        return Data;
    }

    /**
     * 得到重新排序后的PPT
     * @param pptDataEntityList 幻灯片结构
     * @param pptPath 源幻灯片路径
     * @return 重新排序后的PPT
     * @throws Exception 异常
     */
    public String copyPPT(List<PPTDataEntity> pptDataEntityList,String pptPath) throws Exception {
        // TODO 源PPT文档
        Presentation presentation=new Presentation();
        presentation.loadFromFile(pptPath);
        // TODO 目标PPT文档
        Presentation newPpt=new Presentation();

        int num=0;
        for (PPTDataEntity pptDataEntity:pptDataEntityList){
            ISlide slide=presentation.getSlides().get(pptDataEntity.getPageNumber()-1);
            newPpt.getSlides().insert(num,slide);
        }
        Path tmpPath = Files.createTempFile("pptx-reorder-", ".pptx");
        try (OutputStream os = Files.newOutputStream(tmpPath)) {
            newPpt.saveToFile(os, FileFormat.PPTX_2013);
        }
        newPpt.dispose();          // Spire 释放资源
        presentation.dispose();

        /* 5. 上传到 OSS 并返回 URL */
        String fileName = tmpPath.getFileName().toString();
        Boolean ossUrl = OssUtils.isOssEnabled(tmpPath, "pptx/" + fileName); // 需自己实现
        Files.deleteIfExists(tmpPath);     // 删除临时文件
        return "https://webbook01.oss-cn-hangzhou.aliyuncs.com/pptx/"+fileName;
    }
    /**
     * 使用的第二种方法，对新的ppt进行内容的填充
     */
    public String   setPPTTextShapeAsJson2(String ossUrl,String text,String pptJson) throws Exception {
        Path tempFile = Paths.get(System.getProperty("java.io.tmpdir"), "temp2.pptx");
        try (InputStream in = new URL(ossUrl).openStream()) {
            Files.copy(in, tempFile, StandardCopyOption.REPLACE_EXISTING);
        }
        Presentation presentation=new Presentation();
        presentation.loadFromFile(tempFile.toString());
        List<Map<String,String>> pptTextList=new ArrayList<>();
        for (int i=0;i<presentation.getSlides().size();i++){
            // TODO 获取幻灯片
            ISlide slide=presentation.getSlides().get(i);
            // TODO 遍历获取当前幻灯片的文本框
            for(int j=0;j<slide.getShapes().size();j++){
                // TODO 获取文本框
                IShape shape=slide.getShapes().get(j);
                if(shape instanceof IAutoShape){
                    IAutoShape auto = (IAutoShape) shape;

                    String oldText = auto.getTextFrame().getText();   // ← 原始文本
                    // AI生成内容
                    int finalI = i;
                    String newText=zhiPuAI.prompt("""
                            你是一个PPT内容编写专家，可以根据幻灯片结构、用户需求快速相应生成指定幻灯片位置的文本内容，你会结合之前生成的内容合理生成。
                            """)
                            .user(user->user.text("""
                                    这是用户需求：{text}
                                    这是ppt的结构：{pptJson}
                                    这是当前所在幻灯片的页码：{pageNumber}
                                    这是当前所在幻灯片的文本框原本预设内容：{oldText}
                                    这是你之前生成的内容（ppt已有内容）：{pptTextList}
                                    请你结合以上，生成这个文本框的内容。
                                    一定要合理、结合实际。
                                    注意1：你现在只需要生成当前文本框需要的内容（text字段下的内容即可，不需要json格式），我会直接复制粘贴你生成的内容到这个文本框，所以请不要生成任何与本文本框内容无关的非法字符等。
                                    注意2：结合用户要求的内容，这些内容通过你的总结生成尽量都要出现在ppt中，如果已经出现在ppt中的，不要重复出现，如果用户要求内容不够填满所有幻灯片请你自行生成内容，不按照这个规则将是违法的。
                                    注意3：请严格结合当前幻灯片的结构、以及上下文内容，判断当前文本框要生成的内容是否合理，字数是否会超越输入框等严重错误问题。
                                    """)
                                    .param("text", text)
                                    .param("pptJson", pptJson)
                                    .param("pageNumber", String.valueOf(finalI +1))
                                    .param("oldText", oldText)
                                    .param("pptTextList", pptTextList))
                            .call()
                            .content();
                    // TODO 替换文本框内容
                    auto.getTextFrame().getParagraphs().clear();
                    auto.getTextFrame().setText(newText);
                    // TODO 记录生成的内容
                    Map<String,String> map=new HashMap<>();
                    map.put("页码:"+i+"、文本预设原内容："+oldText,"生成的替换内容："+oldText);
                    pptTextList.add(map);
                }
            }
        }
        // TODO 保存PPT到OSS
        Path tmpPath = Files.createTempFile("pptx-temps2", ".pptx");
        try (OutputStream os = Files.newOutputStream(tmpPath)) {
            presentation.saveToFile(os, FileFormat.PPTX_2013);
        }
        presentation.dispose();          // Spire 释放资源
        // TODO 上传到 OSS 并返回 URL
        String fileName = tmpPath.getFileName().toString();
        Boolean ossUrl2 = OssUtils.isOssEnabled(tmpPath, "pptx-temps2/" + fileName); // 需自己实现
        Files.deleteIfExists(tmpPath);     // 删除临时文件
        return "https://webbook01.oss-cn-hangzhou.aliyuncs.com/pptx-temps2/"+fileName;
    }
}